{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1.使用多个界定符分割字符串\n",
    "\n",
    "- re.split()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "line = 'asdf fjdk; afed, fjek,asdf, foo'\n",
    "import re\n",
    "\n",
    "# 分隔符可以是逗号，分号或者是空格，并且后面紧跟着任意个的空格\n",
    "re.split(r'[,;\\s]\\s*', line)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.字符串开头或结尾匹配\n",
    "\n",
    "- str.startswith()\n",
    "- str.endswith()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 单个参数匹配\n",
    "filename = 'spam.txt'\n",
    "filename.endswith('.txt')\n",
    "filename.startswith('file:')\n",
    "\n",
    "# 多个参数匹配\n",
    "# 先调用 tuple() 将其转换为元组类型\n",
    "choices = ['http:', 'ftp:']\n",
    "url = 'http://www.python.org'\n",
    "url.startswith(tuple(choices))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.用Shell通配符匹配字符串\n",
    "\n",
    "使用 Unix Shell 中常用的通配符(比如 *.py , Dat[0-9]*.csv 等)去匹配文本字符串。\n",
    "\n",
    "- fnmatch.fnmatch()\n",
    "  - 使用底层操作系统的大小写敏感规则(不同的系统是不一样的)来匹配模式\n",
    "- fnmatch.fnmatchcase()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['Dat1.csv', 'Dat2.csv']"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from fnmatch import fnmatch, fnmatchcase\n",
    "\n",
    "fnmatch('foo.txt', '*.txt')\n",
    "fnmatch('foo.txt', '?oo.txt')\n",
    "fnmatch('Dat45.csv', 'Dat[0-9]*')\n",
    "\n",
    "names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py']\n",
    "[name for name in names if fnmatch(name, 'Dat*.csv')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# On Mac/Linux => False\n",
    "# On Windows => True\n",
    "fnmatch('foo.txt', '*.txt')\n",
    "\n",
    "# On any => False\n",
    "fnmatchcase('foo.txt', '*.TXT')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4.字符串匹配和搜索\n",
    "\n",
    "基本字符串方法:\n",
    "\n",
    "- str.find()\n",
    "- str.startswitdh()\n",
    "- str.endswitdh()\n",
    "\n",
    "正则匹配：\n",
    "- re.match()\n",
    "  - 总是从字符串开始去匹配\n",
    "- re.findall()\n",
    "  - 搜索文本并以列表形式返回所有的匹配\n",
    "- re.finditer()\n",
    "  - 搜索文本并以以迭代方式返回匹配"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<re.Match object; span=(0, 10), match='11/27/2012'>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "('11', '27', '2012')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "('11', '27', '2012')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[('11', '27', '2012'), ('3', '13', '2013')]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------\n",
      "('11', '27', '2012')\n",
      "('3', '13', '2013')\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "datepat = re.compile(r'(\\d+)/(\\d+)/(\\d+)')\n",
    "\n",
    "m = datepat.match('11/27/2012')\n",
    "m\n",
    "m.group(1), m.group(2) , m.group(3)\n",
    "m.groups()\n",
    "\n",
    "print('-'*20)\n",
    "\n",
    "text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'\n",
    "datepat.findall(text)\n",
    "\n",
    "print('-'*20)\n",
    "\n",
    "for m in datepat.finditer(text):\n",
    "    print(m.groups())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.字符串搜索和替换\n",
    "\n",
    "- str.replace()\n",
    "- re.sub()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'yeah, but no, but yeah, but no, but yeah'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'yep, but no, but yep, but no, but yep'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Today is 11/27/2012. PyCon starts 3/13/2013.'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Today is 2012-11-27. PyCon starts 2013-3-13.'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "('Today is 2012-11-27. PyCon starts 2013-3-13.', 2)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = 'yeah, but no, but yeah, but no, but yeah'\n",
    "text\n",
    "text.replace('yeah', 'yep')\n",
    "\n",
    "text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'\n",
    "text\n",
    "import re\n",
    "re.sub(r'(\\d+)/(\\d+)/(\\d+)', r'\\3-\\1-\\2', text)\n",
    "newtext, n = re.subn(r'(\\d+)/(\\d+)/(\\d+)', r'\\3-\\1-\\2', text)\n",
    "newtext, n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6.字符串忽略大小写的搜索替换\n",
    "\n",
    "需要在使用 re 模块的时候给这些操作提供 re.IGNORECASE 标志参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['PYTHON', 'python', 'Python']"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'UPPER snake, lower snake, Mixed snake'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = 'UPPER PYTHON, lower python, Mixed Python'\n",
    "import re\n",
    "re.findall('python', text, flags=re.IGNORECASE)\n",
    "re.sub('python', 'snake', text, flags=re.IGNORECASE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7.最短匹配模式\n",
    "\n",
    "用正则表达式匹配某个文本模式，但是它找到的是模式的最长可能匹配。而你想修改它变成查找最短的可能匹配。\n",
    "\n",
    "点(.)不能匹配换行符。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['no.']"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['no.\" Phone says \"yes.']"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['no.', 'yes.']"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 问题示例\n",
    "import re\n",
    "re.findall(r'\"(.*)\"', 'Computer says \"no.\"')\n",
    "\n",
    "# 在正则表达式中*操作符是贪婪的，因此匹配操作会查找最长的可能匹配\n",
    "re.findall(r'\"(.*)\"', 'Computer says \"no.\" Phone says \"yes.\"')\n",
    "\n",
    "# 为了修正这个问题，可以在模式中的*操作符后面加上?修饰符，使得匹配变成非贪婪模式\n",
    "re.findall(r'\"(.*?)\"', 'Computer says \"no.\" Phone says \"yes.\"')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8.多行匹配模式\n",
    "\n",
    "重点：\n",
    "- 非捕获组，即(?:)\n",
    "- 点(.)不能匹配换行符"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[' this is a comment ']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[' this is a comment ']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[' this is a\\n multiline comment ']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[' this is a comment ']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[' this is a\\n multiline comment ']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 匹配C语言里的注释行\n",
    "text1 = '/* this is a comment */'\n",
    "text2 = '''/* this is a\n",
    " multiline comment */'''\n",
    "\n",
    "import re\n",
    "re.findall(r'/\\*(.*?)\\*/', text1)\n",
    "re.findall(r'/\\*(.*?)\\*/', text2)\n",
    "\n",
    "print('-'* 20)\n",
    "re.findall(r'/\\*((?:.|\\n)*?)\\*/', text1)\n",
    "re.findall(r'/\\*((?:.|\\n)*?)\\*/', text2)\n",
    "\n",
    "# re.compile() 函数接受一个标志参数叫 re.DOTALL\n",
    "# 它可以让正则表达式中的点(.)匹配包括换行符在内的任意字符。\n",
    "print('-'* 20)\n",
    "re.findall(r'/\\*(.*?)\\*/', text1, re.DOTALL)\n",
    "re.findall(r'/\\*(.*?)\\*/', text2, re.DOTALL)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9.将Unicode文本标准化\n",
    "\n",
    "在处理Unicode字符串，需要确保所有字符串在底层有相同的表示。\n",
    "\n",
    "- 使用unicodedata模块先将文本标准化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('Spicy Jalapeño', 'Spicy Jalapeño')"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "(False, 14, 15)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "('Spicy Jalapeño', 'Spicy Jalapeño', True)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "('Spicy Jalapeño', 'Spicy Jalapeño', True)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import unicodedata\n",
    "\n",
    "# 未将文本标准化\n",
    "s1 = 'Spicy Jalape\\u00f1o'\n",
    "s2 = 'Spicy Jalapen\\u0303o'\n",
    "\n",
    "s1, s2\n",
    "\n",
    "s1 == s2, len(s1), len(s2)\n",
    "\n",
    "print('-'*20)\n",
    "\n",
    "# NFC表示字符应该是整体组成(比如可能的话就使用单一编码)\n",
    "t1 = unicodedata.normalize('NFC', s1)\n",
    "t2 = unicodedata.normalize('NFC', s2)\n",
    "t1, t2, t1==t2\n",
    "\n",
    "# NFD表示字符应该分解为多个组合字符表示\n",
    "t3 = unicodedata.normalize('NFD', s1)\n",
    "t4 = unicodedata.normalize('NFD', s2)\n",
    "t3, t4, t3==t4\n",
    "\n",
    "# 扩展的标准化形式NFKC和NFKD，略...\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 10.在正则式中使用Unicode\n",
    "\n",
    "默认情况下 re 模块已经对一些Unicode字符类有了基本的支持。 \n",
    "\n",
    "比如， \\\\d 已经匹配任意的unicode数字字符了。\n",
    "\n",
    "混合使用Unicode和正则表达式通常会让你抓狂。 如果你真的打算这样做的话，最好考虑下安装第三方正则式库， 它们会为Unicode的大小写转换和其他大量有趣特性提供全面的支持，包括模糊匹配。\n",
    "\n",
    "> 找第三方正则式库"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 11.删除字符串中不需要的字符\n",
    "\n",
    "你想去掉文本字符串开头，结尾或者中间不想要的字符，比如空白。\n",
    "\n",
    "- strip() 方法能用于删除开始或结尾的字符\n",
    "- lstrip() 和 rstrip() 分别从左和从右执行删除操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'hello     world'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'hello     world \\n'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "' hello     world'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'helloworld\\n'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "' hello world '"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = ' hello     world \\n'\n",
    "\n",
    "s.strip()\n",
    "s.lstrip()\n",
    "s.rstrip()\n",
    "\n",
    "# 如果你想处理中间的空格，那么你需要求助其他技术。比如使用 replace() 方法或者是用正则表达式替换。\n",
    "s.replace(' ', '')\n",
    "import re\n",
    "s2 = re.sub('\\s+', ' ', s)\n",
    "s2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 12.审查清理文本字符串\n",
    "\n",
    "- str.translate()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'pýtĥöñ\\x0cis\\tawesome\\r\\n'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'pýtĥöñ is awesome\\n'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'pýtĥöñ is awesome\\n'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'python is awesome\\n'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = 'pýtĥöñ\\fis\\tawesome\\r\\n'\n",
    "s\n",
    "\n",
    "remap = {\n",
    "    ord('\\t') : ' ',\n",
    "    ord('\\f') : ' ',\n",
    "    ord('\\r') : None # Deleted\n",
    "}\n",
    "a = s.translate(remap)\n",
    "a\n",
    "\n",
    "import unicodedata\n",
    "import sys\n",
    "\n",
    "# 通过使用 dict.fromkeys() 方法构造一个字典，每个Unicode和音符作为键，对应的值全部为 None\n",
    "cmb_chrs = dict.fromkeys(c for c in range(sys.maxunicode) if unicodedata.combining(chr(c)))\n",
    "# 使用 unicodedata.normalize() 将原始输入标准化为分解形式字符\n",
    "b = unicodedata.normalize('NFD', a)\n",
    "b\n",
    "\n",
    "b.translate(cmb_chrs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 13.字符串对齐"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'---------Hello World'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Hello World---------'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'----Hello World-----'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'         Hello World'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'---------Hello World'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Hello World         '"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Hello World---------'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'    Hello World     '"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'----Hello World-----'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = 'Hello World'\n",
    "\n",
    "# 基本的字符串对齐操作，可以使用字符串的 ljust() , rjust() 和 center() 方法。\n",
    "text.rjust(20, '-')\n",
    "text.ljust(20, '-')\n",
    "text.center(20, '-')\n",
    "\n",
    "# 函数 format() 同样可以用来很容易的对齐字符串。 你要做的就是使用 <,> 或者 ^ 字符后面紧跟一个指定的宽度。\n",
    "format(text, '>20')\n",
    "format(text, '->20')\n",
    "format(text, '<20')\n",
    "format(text, '-<20')\n",
    "format(text, '^20')\n",
    "format(text, '-^20')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'     Hello      World'"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'     1.234'"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'   1.23   '"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 当格式化多个值的时候，这些格式代码也可以被用在 format() 方法中\n",
    "'{:>10s} {:>10s}'.format('Hello', 'World')\n",
    "\n",
    "# format() 函数的一个好处是它不仅适用于字符串。它可以用来格式化任何值，使得它非常的通用\n",
    "format(1.234, '>10')\n",
    "format(1.234, '^10.2f')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 14.合并拼接字符串\n",
    "\n",
    "- str.join()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Is Chicago Not Chicago?'"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Is, Chicago, Not, Chicago?'"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Is-Chicago-Not-Chicago?'"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "parts = ['Is', 'Chicago', 'Not', 'Chicago?']\n",
    "' '.join(parts)\n",
    "', '.join(parts)\n",
    "\n",
    "\n",
    "def sample():\n",
    "    yield 'Is'\n",
    "    yield 'Chicago'\n",
    "    yield 'Not'\n",
    "    yield 'Chicago?'\n",
    "'-'.join(sample())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 15.字符串中插入变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Guido has 37 messages.'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Guido has 37 messages.'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Python并没有对在字符串中简单替换变量值提供直接的支持。 \n",
    "# 但是通过使用字符串的 format() 方法来解决这个问题。\n",
    "'{name} has {n} messages.'.format(name='Guido', n=37)\n",
    "\n",
    "'{name} has {n} messages.'.format_map({'name':'Guido', 'n':37})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Guido has 27 messages.'"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Guido has {n} messages.'"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# format 和 format_map() 的一个缺陷就是它们并不能很好的处理变量缺失的情况\n",
    "\n",
    "# '{name} has {n} messages.'.format(name='Guido')\n",
    "# KeyError: 'n'\n",
    "\n",
    "# 一种避免这种错误的方法是另外定义一个含有 __missing__() 方法的字典对象\n",
    "class safesub(dict):\n",
    "    def __missing__(self, key):\n",
    "        return '{' + key + '}'\n",
    "\n",
    "'{name} has {n} messages.'.format_map(safesub(name='Guido', n=27))\n",
    "'{name} has {n} messages.'.format_map(safesub(name='Guido'))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 16.以指定列宽格式化字符串\n",
    "\n",
    "- textwrap 模块来格式化字符串的输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Look into my eyes, look into my eyes, the eyes, the eyes, the eyes,\n",
      "not around the eyes, don't look around the eyes, look into my eyes,\n",
      "you're under.\n",
      "--------------------\n",
      "Look into my eyes, look into my eyes,\n",
      "the eyes, the eyes, the eyes, not around\n",
      "the eyes, don't look around the eyes,\n",
      "look into my eyes, you're under.\n",
      "--------------------\n",
      "    Look into my eyes, look into my\n",
      "eyes, the eyes, the eyes, the eyes, not\n",
      "around the eyes, don't look around the\n",
      "eyes, look into my eyes, you're under.\n",
      "--------------------\n",
      "Look into my eyes, look into my eyes,\n",
      "    the eyes, the eyes, the eyes, not\n",
      "    around the eyes, don't look around\n",
      "    the eyes, look into my eyes, you're\n",
      "    under.\n"
     ]
    }
   ],
   "source": [
    "s = \"Look into my eyes, look into my eyes, the eyes, the eyes, \\\n",
    "the eyes, not around the eyes, don't look around the eyes, \\\n",
    "look into my eyes, you're under.\"\n",
    "\n",
    "import textwrap\n",
    "print(textwrap.fill(s, 70))\n",
    "\n",
    "print('-'*20)\n",
    "print(textwrap.fill(s, 40))\n",
    "\n",
    "print('-'*20)\n",
    "print(textwrap.fill(s, 40, initial_indent='    '))\n",
    "\n",
    "print('-'*20)\n",
    "print(textwrap.fill(s, 40, subsequent_indent='    '))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 17.在字符串中处理html和xml\n",
    "\n",
    "你想将HTML或者XML实体如 `&entity;` 或 `&#code;` 替换为对应的文本。 \n",
    "再者，你需要转换文本中特定的字符(比如<, >, 或 &)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Elements are written as \"<tag>text</tag>\".'"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Elements are written as &quot;&lt;tag&gt;text&lt;/tag&gt;&quot;.'"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Elements are written as \"&lt;tag&gt;text&lt;/tag&gt;\".'"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Elements are written as \"<tag>text</tag>\".'"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'Elements are written as \"<tag>text</tag>\".'"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = 'Elements are written as \"<tag>text</tag>\".'\n",
    "s\n",
    "\n",
    "import html\n",
    "\n",
    "html.escape(s)\n",
    "# Disable escaping of quotes\n",
    "html.escape(s, quote=False)\n",
    "\n",
    "html.unescape(html.escape(s))\n",
    "html.unescape(html.escape(s, quote=False))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 18.字符串令牌解析\n",
    "\n",
    "这一小节的内容，不知道有啥用，也没看懂..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 19.实现一个简单的递归下降分析器\n",
    "\n",
    "这一小节内容，很烧脑...\n",
    "\n",
    "我没学过编译原理这门课，所以，没看懂..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 20.字节字符串上的字符串操作\n",
    "\n",
    "几个要点：\n",
    "\n",
    "- 字节字符串同样也支持大部分和文本字符串一样的内置操作\n",
    "- 可以使用正则表达式匹配字节字符串，但是正则表达式本身必须也是字节串\n",
    "- 坦白讲，如果你在处理文本的话，就直接在程序中使用普通的文本字符串而不是字节字符串。不做死就不会死！\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "caf1c2fcf97217de91eafa76b907d50f9ea378f5ffbee7f571142d119bb6a771"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
